using System;
using System.Collections;

namespace SMS.SMPPClient.PDU.Outgoing
{
    /// <summary>
    /// Class for a bind request PDU.
    /// </summary>
    public class SMPPBind : SMPPRequest
    {
        private string _SystemID;
        private string _Password;
        private string _SystemType;
        private string _AddressRange;
        private SMPPVersionType _InterfaceVersion;
        private TONType _AddressTON;
        private NPIType _AddressNPI;

        private const int ID_LENGTH = 15;
        private const int PASS_LENGTH = 8;
        private const int TYPE_LENGTH = 12;
        private const int RANGE_LENGTH = 40;

        /// <summary>
        /// Binding types for the SMPP bind request.
        /// </summary>
        public enum BindingType : uint
        {
            BindAsReceiver = 1,
            BindAsTransmitter = 2,
            BindAsTransceiver = 9
        }

        /// <summary>
        /// SMPP version type.
        /// </summary>
        public enum SMPPVersionType : byte
        {
            Version0_3 = 0x03,
            Version3_3 = 0x33,
            Version3_4 = 0x34
        }

        /// <summary>
        /// Constructs a bind request.
        /// </summary>
        /// <param name="systemID">The ESME system requesting to bind with the SMSC.
        /// Set to null for default value.</param>
        /// <param name="password">Used by the SMSC to authenticate the ESME
        /// requesting to bind.  Set to null for default value.</param>
        /// <param name="systemType">The type of ESME system requesting to bind with
        /// the SMSC.  Set to null for default value.</param>
        /// <param name="interfaceVersion">The version of the SMPP protocol supported by the
        /// ESME.</param>
        /// <param name="addrTON">Indicates type of number of ESME address.</param>
        /// <param name="addrNPI">Numbering plan indicator for ESME address.</param>
        /// <param name="addressRange">The ESME address.  If not known, set to null.</param>
        /// <param name="bindType">Binding type: transmitter, receiver, or transceiver.
        /// </param>
        public SMPPBind(string systemID, string password,
                                string systemType,
                                SMPPVersionType interfaceVersion,
                                TONType addrTON, NPIType addrNPI,
                                string addressRange, BindingType bindType)
        {
            if (systemID != null)
            {
                if (systemID.ToString().Length <= ID_LENGTH)
                    _SystemID = systemID;
                else
                    throw new ArgumentOutOfRangeException(
                        "System ID must be <= " + ID_LENGTH + " characters).");
            }
            else
                _SystemID = "";

            if (password != null)
            {
                if (password.ToString().Length <= PASS_LENGTH)
                    _Password = password;
                else
                    throw new ArgumentOutOfRangeException(
                        "Password must be <= " + PASS_LENGTH + " characters).");
            }
            else
                _Password = "";

            if (systemType != null)
            {
                if (systemType.ToString().Length <= TYPE_LENGTH)
                    _SystemType = systemType;
                else
                    throw new ArgumentOutOfRangeException(
                        "System type must be <= " + TYPE_LENGTH + " characters).");
            }
            else
                _SystemType = "";

            _InterfaceVersion = interfaceVersion;
            _AddressTON = addrTON;
            _AddressNPI = addrNPI;

            if (addressRange != null)
            {
                if (addressRange.ToString().Length <= RANGE_LENGTH)
                    _AddressRange = addressRange;
                else
                    throw new ArgumentOutOfRangeException(
                        "Address range must be <= " + RANGE_LENGTH + " characters).");
            }
            else
                _AddressRange = "";

            _CommandStatus = 0;

            if (bindType == BindingType.BindAsReceiver)
                _CommandID = CommandIDType.bind_receiver;
            else if (bindType == BindingType.BindAsTransceiver)
                _CommandID = CommandIDType.bind_transceiver;
            else if (bindType == BindingType.BindAsTransmitter)
                _CommandID = CommandIDType.bind_transmitter;
        }

        ///<summary>
        /// Gets the hex encoding (big-endian) of this PDU.
        ///</summary>
        ///<return>The hex-encoded version of the PDU</return>
        public override byte[] GetMSBHexEncoding()
        {
            ArrayList pdu = GetPDUHeader();

            pdu.AddRange(ArrayCopyWithNull(
                System.Text.Encoding.ASCII.GetBytes(_SystemID)));

            pdu.AddRange(ArrayCopyWithNull(
                System.Text.Encoding.ASCII.GetBytes(_Password)));

            pdu.AddRange(ArrayCopyWithNull(
                System.Text.Encoding.ASCII.GetBytes(_SystemType)));

            pdu.Add((byte)_InterfaceVersion);
            pdu.Add((byte)_AddressTON);
            pdu.Add((byte)_AddressNPI);

            pdu.AddRange(ArrayCopyWithNull(
                System.Text.Encoding.ASCII.GetBytes(_AddressRange)));

            return EncodePDUForTransmission(pdu);
        }
    }
}
